#include "UserInterface.h"

UserInterface:: UserInterface() {
	
	// the default "configuration" for the application is set in
	// the constructors for "Account" and "OutputProcessor" ..
	_account = new Account();
	
	_showRootMenu = true;
	
	_endSession = false;
	
	_id = -1;
	
	_pn = -1;
	
	_a = -1;
	
	_notAnIntegerMessage = "must be a positive integer value.  Please try again.";
	
	_incorrectMenuSelectionMessage = "Incorrect menu selection.  Please try again.";
	
	currentConfiguration = ConfigurationIds::firstConfiguration;
	
}


UserInterface:: ~UserInterface() {
	
	delete _account;
	
	//cout << "UserInterface:: ~UserInterface() end .. " << endl << endl;
	
}


void UserInterface:: startProgram(){
	
	showApplicationTitle();
	
	while ( !_endSession ) {
		
		//cout << "UserInterface:: startProgram() _showRootMenu: " << _showRootMenu << endl << endl;
		
		if ( _showRootMenu ) {
		
			// this should be in a loop, until:
			// (a) log-in successful, or
			// (b) session ended
			showRootMenu();
		
			string inputString = promptForInput( "", 1000 );
			parseRootMenuInput( inputString );
		
		} else {
		
			// this should be in a loop, until:
			// (a) log-out successful
			
			// this is performed by "OP->display_menu",
			// following each IP->Model->OP operation ..
			//showMainMenu();	
		
			string inputString = promptForInput( ">", 1000 );
			parseMainMenuInput( inputString );
			
		}
		
	} // end "while()" ..
	
	//cout << "UserInterface:: startProgram() end .. " << endl << endl;
	
} // end "startProgram()" ..


void UserInterface:: showApplicationTitle(){
	
	cout << "      BANK ACCOUNT PROGRAM" << endl;
	cout << "CS586 Software System Architecture" << endl;
	cout << "         Steve Talbot" << endl << endl;
	
} // end "showApplicationTitle()" ..


void UserInterface:: showRootMenu(){
	
	cout << endl;
	cout << "==================================" << endl;
	cout << "        MENU SELECTIONS" << endl;
	cout << "==================================" << endl;
	cout << "1) Log In" << endl;
	cout << "2) Open Account" << endl;
	cout << "3) Change Configuration" << endl;
	cout << "4) End Session" << endl;
	cout << endl;
	
} // end "showRootMenu()" ..


void UserInterface:: showConfigurationSubMenu(){
	
	cout << endl;
	cout << "==================================" << endl;
	cout << "     CONFIGURATION SELECTIONS" << endl;
	cout << "==================================" << endl;
	cout << "1) Configuration #1 (default)" << endl;
	cout << "                login: load local account copy, else load file copy" << endl;
	cout << "                  pin: no extra output" << endl;
	cout << "              balance: no extra output" << endl;
	cout << "              deposit: no extra output" << endl;
	cout << "             withdraw: no extra output" << endl;
	cout << "           pin prompt: default prompt " << endl;
	cout << "     incorrect id msg: default message" << endl;
	cout << "too many attempts msg: default message" << endl;
	cout << "         display menu: either \"Activate\" or \"Deactivate\" shown, not both" << endl;
	cout << "       deactivate msg: default message" << endl;
	cout << "        make withdraw: no extra output" << endl;
	cout << "          penalty msg: no extra output" << endl;
	cout << "         make deposit: no extra output" << endl;
	cout << "      display balance: default balance message" << endl;
	cout << "    below min balance: default message" << endl;
	cout << "         activate msg: default message" << endl;
	cout << " inactive account msg: default message" << endl;
	cout << endl;
	cout << "2) Configuration #2" << endl;
	cout << "                login: load file account copy (never local copy)" << endl;
	cout << "                  pin: output # pin \"attempts\" made" << endl;
	cout << "              balance: output \"invoked\" message" << endl;
	cout << "              deposit: output \"min balance\", \"deposit\", \"new balance\"" << endl;
	cout << "             withdraw: output \"min balance\", \"withdraw\", \"new balance\"" << endl;
	cout << "           pin prompt: output alternate prompt" << endl;
	cout << "     incorrect id msg: output alternate message" << endl;
	cout << "too many attempts msg: output alternate message" << endl;
	cout << "         display menu: Both \"Activate / Deactivate\" shown" << endl;
	cout << "       deactivate msg: output alternate message" << endl;
	cout << "        make withdraw: output \"overdrawn\" message when account is overdrawn" << endl;
	cout << "          penalty msg: output \"penalty\" message when account is overdrawn" << endl;
	cout << "         make deposit: output \"overdrawn\" message when account is overdrawn" << endl;
	cout << "      display balance: output alternate balance message" << endl;
	cout << "    below min balance: output alternate message" << endl;
	cout << "         activate msg: output alternate message" << endl;
	cout << " inactive account msg: output alternate message" << endl;
	cout << endl;
	cout << "CURRENT CONFIGURATION: #" << (currentConfiguration + 1) << endl;
	cout << endl;
	
} // end "showConfigurationSubMenu()" ..


void UserInterface:: showMainMenu(){
	
	// Display menu choices to user:
	// balance, deposit, withdraw, activate / deactivate, logout ..
	
	if( currentConfiguration == ConfigurationIds::firstConfiguration ) {
		
		cout << endl;
		cout << "==================================" << endl;
		cout << "          MENU SELECTIONS" << endl;
		cout << "==================================" << endl;
		cout << "1) Balance" << endl;
		cout << "2) Deposit" << endl;
		cout << "3) Withdraw" << endl;
	
		if( _account->getIsActive() == false ){
		
			cout << "4) Activate Account" << endl;
		
		} else {
		
			cout << "4) Deactivate Account" << endl;
		
		}
	
		cout << "5) Current State" << endl;
		cout << "6) Logout" << endl;
		cout << endl;

	} else if( currentConfiguration == ConfigurationIds::secondConfiguration ) {
		
		cout << endl;
		cout << "==================================" << endl;
		cout << "          MENU SELECTIONS" << endl;
		cout << "==================================" << endl;
		cout << "1) Balance" << endl;
		cout << "2) Deposit" << endl;
		cout << "3) Withdraw" << endl;
		cout << "4) Activate / Deactivate Account" << endl;
		cout << "5) Current State" << endl;
		cout << "6) Logout" << endl;
		cout << endl;
		
	}
	
} // end "showMainMenu()" ..


string UserInterface:: promptForInput( string prompt_, int numberOfCharacters_ ){
	
	// prompt for input ..
	if( prompt_.size() > 0 )
		cout << prompt_ << " ";
	else
		cout << "> ";
	
	char input[ numberOfCharacters_ ];
	cin.getline( input, numberOfCharacters_ );
	string inputString = input;
	
	//cout << "inputString[( inputString.size() - 1 )]: " << inputString[( inputString.size() - 1 )] << endl << endl;
	
	//cout << "inputString(before): " << inputString << endl << endl;
	
	// need to strip off the "\r" or "\n" at the end of the input ..
	if( ( inputString[( inputString.size() - 1 )] == '\n' ) ||
		( inputString[( inputString.size() - 1 )] == '\r' ) )
		inputString = inputString.substr( 0, ( inputString.size() - 1 ) );
	
	cout << "inputString: \"" << inputString << "\"" << endl << endl;
	
	return inputString;
	
} // end "promptForInput()" ..
	
	
void UserInterface:: parseRootMenuInput( string inputString_ ){
	
	//cout << "UserInterface:: parseRootMenuInput() start .." << endl << endl;
	
	//cout << "UserInterface:: parseRootMenuInput() inputString: \"" << inputString_ << "\"" << endl << endl;
	
	//cout << "UserInterface:: parseRootMenuInput() inputString.size(): \"" << inputString_.size() << "\"" << endl << endl;
	
	if ( inputString_.size() > 0 ) {
		
		int choice = strToInt( inputString_ );
	
		//cout << "UserInterface:: parseRootMenuInput() choice: " << choice << endl << endl;
	
		if( choice == 1 ){
		
			cout << endl;
		
			// "Log In" selected ..
			if ( currentConfiguration == ConfigurationIds::firstConfiguration )
				cout << "Enter user id";
			else
				cout << "Enter id";
			string inputString = promptForInput( ":", 1000 );
			bool isLoginSuccessful = parseLoginInput( inputString );
		
			if( !isLoginSuccessful ) return;
			else {
			
				// this is done in "OP->prompt_for_pin()" ..
				// cout << "Enter user pin";
			
				string inputString = promptForInput( ":", 1000 );
				parsePinInput( inputString );
			
				cout << endl;
			
			}
		
		} else if( choice == 2 ){
		
			cout << endl;
		
			// "Open Account" selected ..
			if ( currentConfiguration == ConfigurationIds::firstConfiguration )
				cout << "Enter account user id";
			else
				cout << "Enter id";
			string inputString = promptForInput( ":", 1000 );
			bool isIdValid = parseUserIdInput( inputString );
			if( !isIdValid ) return;
		
			if ( currentConfiguration == ConfigurationIds::firstConfiguration )
				cout << "Enter account user pin";
			else
				cout << "Enter pin";
			inputString = promptForInput( ":", 1000 );
			bool isPinValid = parseUserPinInput( inputString );
			if( !isPinValid ) return;
		
			if ( currentConfiguration == ConfigurationIds::firstConfiguration )
				cout << "Enter account initial balance";
			else
				cout << "Enter balance";
			inputString = promptForInput( ":", 1000 );
			bool isBalanceValid = parseAccountBalanceInput( inputString );
			if( !isBalanceValid ) return;
			cout << endl;
		
			// if the input was validated,
			// perform "open account" operation ..
			if( isIdValid && isPinValid && isBalanceValid ){
			
				bool isAccountOpened = _account->open_account( _pn, _id, _a );
			
				if( isAccountOpened ){
				
					if ( currentConfiguration == ConfigurationIds::firstConfiguration )
						cout << "User account was opened - id: " << _id << ", pin: " << _pn << ", balance: " << _a << endl << endl;
					else
						cout << "User account was opened (id: " << _id << ", pin: " << _pn << ", balance: " << _a << ")" << endl << endl;
				
				
				} else {
				
					cout << "User account was NOT opened." << endl << endl;
				
				}
			
			}
		
		} else if( choice == 3 ){
		
			// change the configuration of the system ..
			// display configuration sub-menu ..
		
			showConfigurationSubMenu();
		
			string inputString = promptForInput( ">", 1000 );
			parseConfigurationMenuInput( inputString );
		
		} else if( choice == 4 ){
		
			// "End Session" selected ..
			_endSession = true;
			//cout << "UserInterface:: parseRootMenuInput() _endSession: " << _endSession << endl << endl;
		
		} else {
		
			// user did not enter an "integer" value (i.e.: choice < 0), or
			// user entered an "integer" value that is not supported ..
			cout << _incorrectMenuSelectionMessage << endl << endl;
			
		}
		
	} else {
		
		cout << "Error: user input was not retrieved." << endl << endl;	
		
	}
	

	
} // end "parseRootMenuInput()" ..


bool UserInterface:: parseLoginInput( string inputString_ ){
	
	//cout << "UserInterface:: parseLoginInput() start .." << endl << endl;
	
	bool isLoginSuccessful = true;
	
	int login_y = strToInt( inputString_ );
	
	//cout << "UserInterface:: parseLoginInput() login_y: " << login_y << endl << endl;
	
	if( login_y < 0 ){
		
		// user did not enter an "integer" value ..
		cout << "\"Login\" ";
		cout << _notAnIntegerMessage << endl << endl;
		
		isLoginSuccessful = false;
		
	} else {
		
		//cout << "UserInterface:: parseLoginInput() Point A .." << endl << endl;
		
		// user entered an "integer" value,
		// check this login ..
		isLoginSuccessful = _account->login( login_y );
		
		//cout << "UserInterface:: parseLoginInput() Point B .." << endl << endl;
		
		if( isLoginSuccessful )
			_id = login_y;
		
	}
	
	return isLoginSuccessful;
	
} // end "parseLoginInput()" ..


void UserInterface:: parsePinInput( string inputString_ ){
	
	//cout << "UserInterface:: parsePinInput() start .." << endl << endl;
	
	int pin_p = strToInt( inputString_ );
	
	//cout << "UserInterface:: parsePinInput() pin_p: " << pin_p << endl << endl;
	
	if( pin_p < 0 ){
		
		// user did not enter an "integer" value ..
		cout << "\"Pin\" ";
		cout << _notAnIntegerMessage << endl << endl;
		
	} else {
		
		//cout << "UserInterface:: parsePinInput() Point A .." << endl << endl;
		
		//cout << "UserInterface:: parsePinInput() ( _account == NULL ): " << ( _account == NULL ) << endl << endl;
		
		bool attemptsRemain = true;
		
		// user entered an "integer" value,
		// check this pin ..
		bool isPinSuccessful = _account->pin( pin_p );
		
		//cout << "UserInterface:: parsePinInput() isPinSuccessful: " << isPinSuccessful << endl << endl;
		
		//cout << "UserInterface:: parsePinInput() Point B .." << endl << endl;
		
		if( isPinSuccessful ) {
			
			_showRootMenu = false;
			_pn = pin_p;
				
		} else {
			
			while ( attemptsRemain ) {
				
				
				if ( currentConfiguration == ConfigurationIds::firstConfiguration )
					cout << "Enter user pin";
				else
					cout << "Enter pin";
				
				inputString_ = promptForInput( ":", 1000 );
				
				pin_p = strToInt( inputString_ );
				
				if( pin_p < 0 ){
		
					// user did not enter an "integer" value ..
					cout << "\"Pin\" ";
					cout << _notAnIntegerMessage << endl << endl;
		
				} else {
		
					// user entered an "integer" value,
					// check this pin ..
					isPinSuccessful = _account->pin( pin_p );
					
					//cout << "isPinSuccessful: " << isPinSuccessful << endl << endl;
		
					if( isPinSuccessful ) {
						
						_showRootMenu = false;
						attemptsRemain = false;
						_pn = pin_p;
				
					} else {
						
						//cout << "_account->getStateID(): " << _account->getStateID() << endl << endl;
						//cout << "_account->getAttempts(): " << _account->getAttempts() << endl << endl;
			
						// when number of pin "attempts" reaches max,
						// model returns to "IDLE" state ..
						if( _account->getStateID() == 0 ) {
							
							attemptsRemain = false;
							_showRootMenu = true;
							
						}
			
					}
					
				} // end "if()" ..
			
			} // end "while()" ..
			
		} // end "if()" ..
		
		//cout << "UserInterface:: parsePinInput() Point C .." << endl << endl;
		
		
	} // end "if()" ..
	
	
	
} // end "parsePinInput()" ..


bool UserInterface:: parseUserIdInput( string inputString_ ){
	
	bool result = true;
	
	int login_y = strToInt( inputString_ );
	
	if( login_y < 0 ){
		
		// user did not enter an "integer" value ..
		cout << "\"Login\" ";
		cout << _notAnIntegerMessage << endl << endl;
		
		result = false;
		
	} else {
		
		// set the temp variable, user "_id" ..
		_id = login_y;
		
	}
	
	return result;
	
} // end "parseUserIdInput()" ..


bool UserInterface:: parseUserPinInput( string inputString_ ){
	
	bool result = true;
	
	int pin_p = strToInt( inputString_ );
	
	if( pin_p < 0 ){
		
		// user did not enter an "integer" value ..
		cout << "\"Pin\" ";
		cout << _notAnIntegerMessage << endl << endl;
		
		result = false;
		
	} else {
		
		// set the temp variable, user "_pn" ..
		_pn = pin_p;
		
	}
	
	return result;
	
} // end "parseUserPinInput()" ..


bool UserInterface:: parseAccountBalanceInput( string inputString_ ){
	
	bool result = true;
	
	int balance_b = strToInt( inputString_ );
	
	if( balance_b < 0 ){
		
		// user did not enter an "integer" value ..
		cout << "Initial \"balance\" amount ";
		cout << _notAnIntegerMessage << endl << endl;
		
		result = false;
		
	} else {
		
		// set the temp variable, user "_a" ..
		_a = balance_b;
		
	}
	
	return result;
	
} // end "parseAccountBalanceInput()" ..


void UserInterface:: parseConfigurationMenuInput( string inputString_ ){

/*
	cout << "========================" << endl;
	cout << "CONFIGURATION SELECTIONS" << endl;
	cout << "========================" << endl;
	cout << "1) Configuration #1 (default)" << endl;
	cout << "2) Configuration #2" << endl;
*/

	bool configurationLoaded = false;

	int choice = strToInt( inputString_ );
	
	if( choice == 1 ){

		// go with "Configuration #1 (default)" ..
		ConfigurationFactory1* cf1 = new ConfigurationFactory1();
		
		loadConfiguration( cf1 );
		
		currentConfiguration = ConfigurationIds::firstConfiguration;
		
		configurationLoaded = true;
		
	} else if( choice == 2 ){
		
		// go with "Configuration #2" ..
		ConfigurationFactory* cf2 = new ConfigurationFactory2();
		
		loadConfiguration( cf2 );
		
		currentConfiguration = ConfigurationIds::secondConfiguration;
		
		configurationLoaded = true;
		
	} else {
		
		// user did not enter an "integer" value (i.e.: choice < 0), or
		// user entered an "integer" value that is not supported ..
		cout << _incorrectMenuSelectionMessage << endl << endl;
		
	}
	
	if( configurationLoaded == true )
		cout << "Configuration #" << choice << " was loaded." << endl << endl;
	else
		cout << "Configuration #" << choice << " NOT was loaded." << endl << endl;
	
} // end "parseConfigurationMenuInput()" ..


void UserInterface:: loadConfiguration( ConfigurationFactory* cf_ ){
	
	_account->removeCurrentConfiguration();
	
	_account->setLoginA( cf_->makeLogin() );
	_account->setPinA( cf_->makePin() );
	_account->setDepositA( cf_->makeDeposit() );
	_account->setWithdrawA( cf_->makeWithdraw() );
	_account->setBalanceA( cf_->makeBalance() );
	
	OutputProcessor* OP = _account->getOutputProcessor();
	
	OP->removeCurrentConfiguration();
	
	OP->setPromptForPinA( cf_->makePromptForPin() );
	OP->setIncorrectIdMsgA( cf_->makeIncorrectIdMsg() );
	OP->setIncorrectPinMsgA( cf_->makeIncorrectPinMsg() );
	OP->setTooManyAttemptsMsgA( cf_->makeTooManyAttemptsMsg() );
	OP->setDisplayMenuA( cf_->makeDisplayMenu() );
	OP->setDeactivateMsgA( cf_->makeDeactivateMsg() );
	OP->setMakeWithdrawMsgA( cf_->makeMakeWithdraw() );
	OP->setPenaltyA( cf_->makePenalty() );
	OP->setMakeDepositA( cf_->makeMakeDeposit() );
	OP->setDisplayBalanceA( cf_->makeDisplayBalance() );
	OP->setBelowMinBalanceMsgA( cf_->makeBelowMinBalance() );
	OP->setActivateMsgA( cf_->makeActivateMsg() );
	OP->setInactiveAccountMsgA( cf_->makeInactiveAccountMsg() );
	
}


void UserInterface:: parseMainMenuInput( string inputString_ ){

/*
	cout << "MENU SELECTIONS" << endl;
	cout << "================" << endl;
	cout << "1) Balance" << endl;
	cout << "2) Deposit" << endl;
	cout << "3) Withdraw" << endl;
	if( data_->getCurrentAccountInfo()->getIsActive() == false ){
		cout << "4) Activate account" << endl;
	} else {
		cout << "4) Deactivate account" << endl;
	}
	cout << "5) Logout" << endl;
*/

	int choice = strToInt( inputString_ );

	if( choice == 1 ){

		// "Balance" selected ..
		_account->balance();

	} else if( choice == 2 ){
		
		// "Deposit" selected ..
		
		bool isDepositAmountValid = false;
		
		if( _account->getIsActive() == false ) {
			
			// "model" will indicate to "OP" to output a message 
			// saying that the transaction cannot be performed,
			// b/c the account is "inactive" ..
			isDepositAmountValid = _account->deposit( 0 );
			
		} else {
			
			cout << "Enter \"deposit\" amount";
			string inputString = promptForInput( ":", 1000 );
			isDepositAmountValid = parseDepositAmountInput( inputString );
			
		}
		
	} else if( choice == 3 ){
		
		// "Withdraw" selected ..
		
		bool isWithdrawAmountValid = false;
		
		if( ( _account->getIsActive() == false ) || 
			( _account->getIsOverdrawn() == true ) ) {
			
			// "model" will indicate to "OP" to output a message 
			// saying that the transaction cannot be performed,
			// b/c the account is "inactive" or "overdrawn" ..
			isWithdrawAmountValid = _account->withdraw( 0 );
			
		} else {
			
			cout << "Enter \"withdraw\" amount";
			string inputString = promptForInput( ":", 1000 );
			isWithdrawAmountValid = parseWithdrawAmountInput( inputString );
			
		}
			
	} else if( choice == 4 ){
		
		// "Activate" / "Deactivate" selected ..
		
		bool result = false;
		
		if( _account->getIsActive() == true )
			result = _account->deactivate();
		else
			result = _account->activate();
		
	} else if( choice == 5 ){
		
		// "Current State" selected ..
		
		cout << "Current state: " << _account->getState() << endl << endl;
		
		// this is needed here, because "show current state" operation
		// is not supported by the "IP->Model->OP" architecture ..
		showMainMenu();

		
	} else if( choice == 6 ){
		
		// "Logout" selected ..
		_account->logout();
		
		_showRootMenu = true;
		
		if ( currentConfiguration == ConfigurationIds::firstConfiguration )
			cout << "The user was \"logged out\" - id: " << _id << endl << endl;
		else
			cout << "The user was \"logged out\" (id: " << _id << ")" << endl << endl;
		
	} else {
		
		// user did not enter an "integer" value (i.e.: choice < 0), or
		// user entered an "integer" value that is not supported ..
		cout << _incorrectMenuSelectionMessage << endl << endl;
		
	}
	
} // end "parseMainMenuInput()" ..


bool UserInterface:: parseDepositAmountInput( string inputString_ ){
	
	bool result = true;
	
	int deposit_d = strToInt( inputString_ );
	
	if( deposit_d < 0 ){
		
		// user did not enter an "integer" value ..
		cout << "\"Deposit\" amount ";
		cout << _notAnIntegerMessage << endl << endl;
		
		result = false;
		
	} else {
		
		//cout << "_account->getState(): " << _account->getState() << endl << endl;

		result = _account->deposit( deposit_d );
		
	}
	
	return result;
	
} // end "parseDepositAmountInput()" ..


bool UserInterface:: parseWithdrawAmountInput( string inputString_ ){
	
	bool result = true;
	
	int withdraw_w = strToInt( inputString_ );
	
	if( withdraw_w < 0 ){
		
		// user did not enter an "integer" value ..
		cout << "\"Withdraw\" amount ";
		cout << _notAnIntegerMessage << endl << endl;
		
		result = false;
		
	} else {
		
		//cout << "_account->getState(): " << _account->getState() << endl << endl;

		result = _account->withdraw( withdraw_w );
		
	}
	
	return result;
	
} // end "parseWithdrawAmountInput()" ..


